﻿using AutoMapper;
using KWT.DRG_DIP.DO.Group;
using KWT.DRG_DIP.DO.Group.DIPGroup;
using KWT.DRG_DIP.DO.Group.DIPGroup.Enum;
using KWT.DRG_DIP.DO.Group.DRGGroup;
using KWT.DRG_DIP.DTO.Group;

namespace KWT.DRG_DIP.Svc.Group.DIPGroup
{

    public class DIPGroup : DIPGroupBase
    {
        
        public override GroupResultBase GroupExecue(GroupInputParaBase inputPara)
        {            
            DIPGroupResult dIPGroupResult= GetDiseaseGroup((DIPGroupInputPara)inputPara);
            GetAssist((DIPGroupInputPara)inputPara, dIPGroupResult);
            return dIPGroupResult;
        }

        #region 获得辅助目录
        /// <summary>
        /// 获得辅助目录
        /// </summary>
        /// <param name="inputPara"></param>
        /// <param name="dIPGroupResult"></param>
        /// <returns></returns>
        private DIPGroupResult GetAssist(DIPGroupInputPara inputPara, DIPGroupResult dIPGroupResult)
        {
            if (!dIPGroupResult.Success)
            {
                return dIPGroupResult;
            }
            string diseaseCode = dIPGroupResult.strResult;
            //根据病种组获得 辅助目录标杆
            List<DIP_Assist> dIP_AssistsDisease = dIP_Assists.Where(x => x.Disease_Code == diseaseCode).ToList();

            //验证满足哪些辅助目录
            List<DIP_Assist> lstResult = new List<DIP_Assist>();
            DIP_Assist? assist;

            #region 辅助目录  恶性肿瘤严重程度分型
            if (dIP_AssistsDisease.Any(x => x.Type == EnumAssistType.恶性肿瘤严重程度分型.ToString()))
            {
                var assistsTumor = dIP_AssistsDisease.Where(x => x.Type == EnumAssistType.恶性肿瘤严重程度分型.ToString()).ToList();
                var temp = EXZLFX(inputPara);
                if (temp.Success)
                {
                    assist = tatransformCode(assistsTumor, temp.strResult);
                    if (assist != null)
                    {
                        assist.Msg = temp.msg + ";" + assist.Msg;
                        lstResult.Add(assist);
                    }
                }
            }
            #endregion

            #region 辅助目录  DIP疾病严重程度分型

            if (dIP_AssistsDisease.Any(x => x.Type == EnumAssistType.DIP疾病严重程度分型.ToString()))
            {
                var assistsTumor = dIP_AssistsDisease.Where(x => x.Type == EnumAssistType.DIP疾病严重程度分型.ToString()).ToList();
                var temp = YZCDFX(inputPara);
                if (temp.Success)
                {
                    assist = tatransformCode(assistsTumor, temp.strResult);
                    if (assist != null)
                    {
                        assist.Msg = temp.msg + ";" + assist.Msg;
                        lstResult.Add(assist);
                    }
                }
            }
            #endregion

            //满足的辅助目录 获得 调节系数 最高的结果
            DIP_Assist? _Assist = lstResult.OrderByDescending(x => x.Ratio).FirstOrDefault();
            if(lstResult.Count>1)
            {
                string Msg = "";
                foreach (var item in lstResult)
                {
                    Msg += $"{item.Type}:{item.Code};";
                }
                _Assist.Msg += Msg;
            }
            dIPGroupResult.dIP_Assist = _Assist;

            return dIPGroupResult;
        }
        #endregion

        #region 获得病种组
        /// <summary>
        /// 获得病种组
        /// </summary>
        /// <param name="inputPara"></param>
        /// <returns></returns>
        private DIPGroupResult GetDiseaseGroup(DIPGroupInputPara inputPara)
        {
            DIPGroupResult result = new DIPGroupResult();

            if (inputPara.operation == null || inputPara.operation.Count == 0)
            {
                #region step1.1: 无手术，主诊亚目与无手术的核心组完全匹配
                var diseaseGroup = dIP_Rule_DiseaseGroups.Where(x => x.DiseaseGroupType == "核心病种" && x.MainOperationCode == ""
                                        && inputPara.Suborder.Equals(x.MainDiagnoseCode, StringComparison.OrdinalIgnoreCase))
                                        .OrderByDescending(x => x.Score).FirstOrDefault();
                if (diseaseGroup != null)
                {
                    result = new DIPGroupResult()
                    {
                        Success = true,
                        strResult = diseaseGroup.DiseaseGroupCode,
                        msg = "无手术，与该主诊亚目下无手术的核心病种组完全匹配",

                    };
                    return result;
                }
                #endregion

                #region step1.2: 无手术，主诊类目与综合组 保守治疗组 匹配
                diseaseGroup = dIP_Rule_DiseaseGroups.Where(x => x.DiseaseGroupType == "综合病种" && x.MainOperationCode == EnumOperationType.BSZL.ToString()
                                        && inputPara.Category.Equals(x.MainDiagnoseCode, StringComparison.OrdinalIgnoreCase))
                                        .OrderByDescending(x => x.Score).FirstOrDefault();
                if (diseaseGroup != null)
                {
                    result = new DIPGroupResult()
                    {
                        Success = true,
                        strResult = diseaseGroup.DiseaseGroupCode,
                        msg = "无手术，与该主诊类目下 综合病种 保守治疗 匹配 ",

                    };
                    return result;
                }
                else
                {
                    result = new DIPGroupResult()
                    {
                        Success = false,
                        strResult = "",
                        msg = "无手术，入组失败,该主诊类目下无“保守治疗” ",

                    };
                    return result;
                }
                #endregion
            }
            else
            {
                #region step2.1 :主诊亚目+主手与 核心病种匹配
                //主诊亚目+主手术确定若干病种组
                var diseaseGroups = dIP_Rule_DiseaseGroups.Where(x => x.DiseaseGroupType == "核心病种"
                                        && inputPara.operation.Any(y => y.IsMain == 1 && y.medicalInsuranceCode.Equals(x.MainOperationCode, StringComparison.OrdinalIgnoreCase))
                                        && inputPara.Suborder.Equals(x.MainDiagnoseCode, StringComparison.OrdinalIgnoreCase)).ToList();

                var dIPMiddResults = GetDIPMiddResults(inputPara, diseaseGroups);

                var dIPMiddResult = dIPMiddResults.OrderByDescending(x => x.ConditionCount).ThenByDescending(x => x.Score).FirstOrDefault();

                if (dIPMiddResult != null)
                {
                    result = new DIPGroupResult()
                    {
                        Success = true,
                        strResult = dIPMiddResult.code,
                        msg = $"主诊亚目+主手与 核心病种匹配,相关手术匹配最多为{dIPMiddResult.ConditionCount}",

                    };
                    return result;
                }
                #endregion

                #region step2.2 :主诊类目与综合病种匹配

                //获得 该主诊类目的综合病种：诊断性操作/治疗性操作/手术/保守治疗
                diseaseGroups = dIP_Rule_DiseaseGroups.Where(x => x.DiseaseGroupType == "综合病种"
                                      && inputPara.Category.Equals(x.MainDiagnoseCode, StringComparison.OrdinalIgnoreCase)).ToList();

                //获得手术类别
                string MainOperation = inputPara.operation.FirstOrDefault(x => x.IsMain == 1)?.medicalInsuranceCode ?? "";
                //从数据库中获得手术类别
                OperInfo? operationType = dIP_Operation_Info.FirstOrDefault(x => x.InsuranceCode.Equals(MainOperation, StringComparison.OrdinalIgnoreCase));
                if (operationType == null)
                {
                    operationType = new OperInfo();
                }
                #region 主手术与该主诊类目下 综合病种 匹配
                var zhbzGroup = diseaseGroups.FirstOrDefault(x => x.MainOperationCode.Equals(operationType.TypeCode));
                if (zhbzGroup != null)
                {
                    result = new DIPGroupResult()
                    {
                        Success = true,
                        strResult = zhbzGroup.DiseaseGroupCode,
                    };
                    switch (zhbzGroup.MainOperationCode)
                    {
                        case "ZDXCZ":
                            result.msg = "主手术与该主诊类目下 综合病种 诊断性操作 匹配 ";
                            break;
                        case "ZLXCZ":
                            result.msg = "主手术与该主诊类目下 综合病种 治疗性操作 匹配 ";
                            break;
                        case "SS":
                            result.msg = "主手术与该主诊类目下 综合病种 手术 匹配 ";
                            break;
                        case "BSZL":
                            result.msg = "主手术与该主诊类目下 综合病种 保守治疗 匹配 ";
                            break;
                        default:
                            break;
                    }
                    return result;
                }
                #endregion

                #region 主手术与该主诊类目下 综合病种 不匹配，但有 保守治疗
                var zhbz_bszl = diseaseGroups.FirstOrDefault(x => x.DiseaseGroupType == "综合病种" && x.MainOperationCode == EnumOperationType.BSZL.ToString());

                if (zhbz_bszl != null)
                {
                    result = new DIPGroupResult()
                    {
                        Success = true,
                        strResult = zhbz_bszl.DiseaseGroupCode,
                        msg = "主手术与该主诊类目下 综合病种不匹配，有保守治疗 入保守治疗 ",
                    };
                    return result;
                }
                #endregion

                #region 入组失败
                string Msg = "";
                foreach (var disease in diseaseGroups)
                {
                    switch (disease.MainOperationCode)
                    {
                        case "ZDXCZ":
                            Msg += "诊断性操作、";
                            break;
                        case "ZLXCZ":
                            Msg += "治疗性操作、";
                            break;
                        case "SS":
                            Msg += "手术、";
                            break;
                        case "BSZL":
                            Msg += "保守治疗、";
                            break;
                        default:
                            break;
                    }
                }
                Msg = Msg.TrimEnd('、');

                if (Msg != "")
                {
                    result = new DIPGroupResult()
                    {
                        Success = false,
                        strResult = "",
                        msg = $"入组失败，该主诊类目下仅有{Msg}",
                    };
                    return result;
                }
                else
                {
                    result = new DIPGroupResult()
                    {
                        Success = false,
                        strResult = "",
                        msg = $"入组失败，该主诊类目下无综合病种",
                    };
                    return result;
                }
                #endregion


                #endregion
            }
        }
        #endregion

        #region 获得 其他手术完全匹配的病种组
        /// <summary>
        /// 获得 其他手术完全匹配的病种组
        /// </summary>
        /// <param name="inputPara"></param>
        /// <param name="diseaseGroups"></param>
        /// <returns></returns>
        private List<DIPMiddResult> GetDIPMiddResults(DIPGroupInputPara inputPara, List<DIP_Rule_DiseaseGroup> diseaseGroups)
        {
            List<DIPMiddResult> dIPMiddResults = new List<DIPMiddResult>();

            foreach (var disease in diseaseGroups)
            {
                if (!string.IsNullOrEmpty(disease.OtherOperationCode))
                {
                    //病种组 其他手术以+分割
                    List<string> lstConditions = disease.OtherOperationCode.Split("+").ToList();
                    //病种组 其他手术 全部在 患者的其他手术 内
                    if (lstConditions.All(x => inputPara.operation.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x, StringComparison.OrdinalIgnoreCase))))
                    {
                        DIPMiddResult dIPMidd = new DIPMiddResult()
                        {
                            code = disease.DiseaseGroupCode,
                            ConditionCount = lstConditions.Count,
                            Score = disease.Score
                        };
                        dIPMiddResults.Add(dIPMidd);
                    }
                }
                else
                {
                    //病种组没有其他手术，说明只有主诊，主手匹配
                    DIPMiddResult dIPMidd = new DIPMiddResult()
                    {
                        code = disease.DiseaseGroupCode,
                        ConditionCount = 0,
                        Score = disease.Score
                    };
                    dIPMiddResults.Add(dIPMidd);
                }
            }

            return dIPMiddResults;
        }
        #endregion

        #region 恶性肿瘤严重程度分型
        /// <summary>
        /// 恶性肿瘤严重程度分型
        /// </summary>
        /// <param name="inputPara"></param>
        /// <returns></returns>
        private DIPGroupResult EXZLFX(DIPGroupInputPara inputPara)
        {
            DIPGroupResult result = new DIPGroupResult();

            #region 离院方式:死亡，住院天数<=3天
            if (inputPara.LeaveType == 1 && inputPara.Days <= 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "VI-A",
                    msg = $"离院方式:死亡，住院天数<=3天",

                };
                return result;
            }
            #endregion

            #region 离院方式:死亡，住院天数>3天
            if (inputPara.LeaveType == 1 && inputPara.Days > 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "VI-B",
                    msg = $"离院方式:死亡，住院天数>3天",

                };
                return result;
            }

            #endregion

            #region 离院方式:非死亡，手术有化疗操作"

            //是否有化疗操作
            bool bHL = dIP_Rules.Any(x => x.RuleType == EnumRuleType.化疗 &&
                     inputPara.operation.Any(y => y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));

            if (bHL)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "V-B",
                    msg = $"离院方式:非死亡，手术有化疗操作",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术有放疗操作
            //是否有放疗操作
            bool bFL = dIP_Rules.Any(x => x.RuleType == EnumRuleType.放疗 &&
                    inputPara.operation.Any(y => y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            if (bFL)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "V-A",
                    msg = $"离院方式:非死亡，手术有放疗操作",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术无化疗、放疗操作，住院天数<=3天
            if (inputPara.Days <= 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "I-A",
                    msg = $"离院方式:非死亡，手术无化疗、放疗操作，住院天数<=3天",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含肿瘤诊断且前三位编码与主诊不相同
            bool bZL = dIP_Rules.Any(x => x.RuleType == EnumRuleType.恶性肿瘤 && x.OperationCode.Substring(1, 3) != inputPara.Category &&
                     inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));

            if (bZL)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "IV",
                    msg = $"离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含肿瘤诊断且前三位编码与主诊不相同",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含“功能衰竭”、“休克”、“菌血症”、“脓毒血症”
            //含“功能衰竭”
            bool bGNSJ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.功能衰竭 &&
                inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“休克诊断”
            bool bXK = dIP_Rules.Any(x => x.RuleType == EnumRuleType.休克诊断 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“菌血症”
            bool bJXZ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.菌血症 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“脓毒血症”
            bool bNDXZ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.脓毒血症 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));

            if (bGNSJ || bXK || bJXZ || bNDXZ)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "III",
                    msg = $"离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含“功能衰竭”、“休克”、“菌血症”、“脓毒血症”",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含“重要脏器病损+重要脏器感染”
            bool bZYZQ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.重要脏器病损或感染 &&
             inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            if (bZYZQ)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "II",
                    msg = $"离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断含“重要脏器病损+重要脏器感染”",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断不含前三项或其他诊断为空
            result = new DIPGroupResult()
            {
                Success = true,
                strResult = "I-B",
                msg = $"离院方式:非死亡，手术无化疗、放疗操作，住院天数>3天,其他诊断不含前三项或其他诊断为空",

            };
            return result;
            #endregion
        }
        #endregion

        #region DIP疾病严重程度分型辅助目录
        /// <summary>
        /// DIP疾病严重程度分型辅助目录
        /// </summary>
        /// <param name="inputPara"></param>
        /// <returns></returns>
        private DIPGroupResult YZCDFX(DIPGroupInputPara inputPara)
        {
            DIPGroupResult result = new DIPGroupResult();

            #region 离院方式:死亡，住院天数<=3天
            if (inputPara.LeaveType == 1 && inputPara.Days <= 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "IV-A",
                    msg = $"离院方式:死亡，住院天数<=3天",

                };
                return result;
            }
            #endregion

            #region 离院方式:死亡，住院天数>3天
            if (inputPara.LeaveType == 1 && inputPara.Days > 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "IV-B",
                    msg = $"离院方式:死亡，住院天数>3天",

                };
                return result;
            }

            #endregion

            #region 离院方式:非死亡，无其他诊断
            if (inputPara.diagnoses.Count <= 1)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "I",
                    msg = $"离院方式:非死亡，无其他诊断",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，有其他诊断，住院天数<= 3天
            if (inputPara.diagnoses.Count > 1 && inputPara.Days <= 3)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "I",
                    msg = $"离院方式:非死亡，有其他诊断，住院天数<= 3天",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，有其他诊断，住院天数> 3天

            //含“功能衰竭”
            bool bGNSJ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.功能衰竭 &&
                inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“休克诊断”
            bool bXK = dIP_Rules.Any(x => x.RuleType == EnumRuleType.休克诊断 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“菌血症”
            bool bJXZ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.菌血症 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            //含“脓毒血症”
            bool bNDXZ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.脓毒血症 &&
            inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));

            if (bGNSJ || bXK || bJXZ || bNDXZ)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "III",
                    msg = $"离院方式:非死亡，有其他诊断，住院天数> 3天,其他诊断含“功能衰竭”、“休克”、“菌血症”、“脓毒血症”",

                };
                return result;
            }

            #endregion

            #region 离院方式:非死亡，有其他诊断，住院天数> 3天,其他诊断含“重要脏器病损+重要脏器感染”
            bool bZYZQ = dIP_Rules.Any(x => x.RuleType == EnumRuleType.重要脏器病损或感染 &&
             inputPara.diagnoses.Any(y => y.IsMain == 0 && y.medicalInsuranceCode.Equals(x.OperationCode, StringComparison.OrdinalIgnoreCase)));
            if (bZYZQ)
            {
                result = new DIPGroupResult()
                {
                    Success = true,
                    strResult = "II",
                    msg = $"离院方式:非死亡，有其他诊断，住院天数> 3天,其他诊断含“重要脏器病损+重要脏器感染”",

                };
                return result;
            }
            #endregion

            #region 离院方式:非死亡，有其他诊断，住院天数> 3天,不符合II 、III级的病例
            result = new DIPGroupResult()
            {
                Success = true,
                strResult = "I",
                msg = $"离院方式:非死亡，有其他诊断，住院天数> 3天,不符合II 、III级的病例 ",

            };
            return result;
            #endregion
        }
        #endregion

        #region 转换辅助目录级别Code
        string[] levels = { "I", "I-A", "I-B", "II", "II-A", "II-B", "III", "III-A", "III-B", "IV", "IV-A", "IV-B", "V", "V-A", "V-B", "VI", "VI-A", "VI-B", };


        /// <summary>
        /// 转换辅助目录级别Code
        /// 如该级别不存在，则先获取小于该级别最近的
        /// 如还不存在，则获取大于该级别最近的
        /// </summary>
        private DIP_Assist? tatransformCode(List<DIP_Assist> assists, string code)
        {
            DIP_Assist? assist = assists.FirstOrDefault(x => x.Code == code);
            if (assist != null)
            {
                return assist;
            }

            var assistsSort = assists.Select(x => new { x.Code, sort = Array.IndexOf(levels, x.Code) });

            //小于 code 的最大级别
            string? codeNew = assistsSort.Where(y => y.sort <= Array.IndexOf(levels, code)).OrderByDescending(x => x.sort).Select(x => x.Code).FirstOrDefault();
            if (!string.IsNullOrEmpty(codeNew))
            {
                assist = assists.FirstOrDefault(x => x.Code == codeNew);
                assist.Msg = $"辅助目录无{code}，靠近入{codeNew}";
                return assist;
            }

            //大于 code 的最小级别
            codeNew = assistsSort.Where(y => y.sort > Array.IndexOf(levels, code)).OrderBy(x => x.sort).Select(x => x.Code).FirstOrDefault();
            assist = assists.FirstOrDefault(x => x.Code == codeNew);
            assist.Msg = $"辅助目录无{code}，靠近入{codeNew}";
            return assist;

        }
        #endregion
    }
}
